#include <atomic>
#include <chrono>
#include <cmath>
#include <csignal>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <thread>

#include "RedefineGuard"
#include "animation.hpp"
#include "card.h"
#include "containor.h"
#include "drawer.h"
#include "getwindow.h"
#include "logging.hpp"
#include "screenbuffer.h"
#include "updater.h"

std::atomic<bool> keepRunning(true);
std::atomic<bool> needRefrash(true);
std::atomic<bool> WindowSizeChanged(true);
ScreenBuffer_t buffer;
void signalHandler(int signum)
{
    printf("Signal %d Captured", signum);
    keepRunning.store(false);
}

void timer()
{
    srand(static_cast<unsigned int>(time(0)));
    buffer.GetWindowSize();
    Coord_t temp;
    Coord_t Cardpos{1, 1};
    Coord_t Cardsize{18, 15};
    unsigned long long int s{0};
    unsigned long long int a{0};
    double breathEffectTimer{0};
    bool revertBreath{false};
    double bounceEffectTimer{0};
    bool revertBounce{false};
    buffer.Fill(' ');
    std::string testtitle{"WindowTitle :D"};
    std::string testcontent{"This is a long text that made for testing the functionality."};
    std::string placeholder{
        "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut "
        "labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco "
        "laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in "
        "voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat "
        "cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."};
    Card* ACard = new Card({1, 3}, {18, 15}, testtitle, placeholder, '|', ' ', &buffer.drawer);
    Card* BCard = new Card({1, 3}, {18, 15}, "Card B", placeholder, '|', ' ', &buffer.drawer);
    Card* CCard = new Card({1, 3}, {18, 15}, "Card C", placeholder, '|', ' ', &buffer.drawer);
    Card* DCard = new Card({1, 3}, {18, 15}, "This is Card_D", placeholder, '|', ' ', &buffer.drawer);
    Containor* BasePage = new Containor({0, 0}, buffer._WindowSize, '#', &buffer.drawer);
    Containor* Apage = new Containor({1, 1}, {2, 2}, '#', &buffer.drawer);
    Containor* Bpage = new Containor({10, 10}, {10, 10}, '#', &buffer.drawer);
    Containor** Layout = new Containor*[20];
    for (int i = 0; i < 20; i++)
    {
        Layout[i] = new Containor;
    }
    BasePage->Load(ACard, nullptr, nullptr, nullptr);
    // BasePage->Load(Apage, Layout[18], ACard, Layout[19]);
    // Layout[18]->Load(Layout[7], Layout[6], BCard, Layout[16]);
    // Layout[19]->Load(Layout[1], Layout[0], Layout[3], Layout[4]);
    // Layout[16]->Load(Layout[10], Layout[11], Layout[12], Layout[13]);
    // // Layout[13]->Load(nullptr, nullptr, nullptr, CCard);
    // Layout[13]->Load(nullptr, nullptr, nullptr, DCard);
    // Layout[4]->Load(DCard, nullptr, CCard, CCard);

    while (keepRunning)
    { // simple draw queue of render

        buffer.GetWindowSize(temp);
        if (buffer._WindowSize != temp)
        {
            buffer._WindowSize = temp;
            needRefrash = true;
            WindowSizeChanged = true;
        }
        // buffer._WindowSize = {119, 32};
        // temp = {119, 32};

        buffer.Fill(' ');
        static short x{12};
        needRefrash = true;
        if (breathEffectTimer < 0)
        {
            revertBreath = false;
        }
        else if (breathEffectTimer >= 1)
        {
            revertBreath = true;
        }
        if (bounceEffectTimer < 0)
        {
            revertBounce = false;
        }
        else if (bounceEffectTimer >= 1)
        {
            revertBounce = true;
        }
        if (s % 12000)
        {
            if (!revertBreath)
                breathEffectTimer += 0.008;
            else
                breathEffectTimer -= 0.008;
            if (!revertBounce)
                bounceEffectTimer += 0.02;
            else
                bounceEffectTimer -= 0.02;

            easeInOutQuint(Cardpos.X, 0, 13, breathEffectTimer);
            easeInOutQuint(Cardpos.Y, 0, 5, breathEffectTimer);
            easeInOutExpo(Cardsize.X, 0, -26, breathEffectTimer);
            easeInOutExpo(Cardsize.Y, 0, -10, breathEffectTimer);
            easeInOutExpo(x, 0, -260, breathEffectTimer);
            // Mapping(x, 0, -26, 0, -260);
            // Mapping(x, 0, -10, 0, -260);
            //  easeInOutExpo(x, 8, 135, bounceEffectTimer);

            // clang-format off
            buffer.updater(ACard)
                .Position(Cardpos)
                .Size({short(trunc(x/10)),short(trunc(x/26))})
            //.FillStyle(' ')
                .Commit();
            buffer.updater(BasePage)
                .Size(buffer.FullScreenSize)
                .Commit();
            // clang-format on
        }
        BasePage->render();
        // ACard->render();
        std::this_thread::sleep_for(std::chrono::microseconds(20));
        s++;
    }
    delete BasePage;
    // delete ACard;
    delete Apage;
    delete Bpage;
    delete[] Layout;
}
extern int show_cursor();
extern int hide_cursor();
extern int HideScrollbar();
int windows_api_test()
{
    hide_cursor();
    signal(SIGINT, signalHandler);
    std::thread renderThread(timer);
    while (keepRunning)
    {
        // printf("\033[1;1H");
        if (WindowSizeChanged)
        {
        }
        if (needRefrash)
        {
            buffer.Display(&buffer);
            LOG::ShowAll();
            needRefrash = false;
            std::this_thread::sleep_for(std::chrono::microseconds(4166));
        }
    }
    renderThread.join();
    show_cursor();
    return 0;
}

void EventTest() {}

int main()
{
    Loadin_Redefine_Guard();
    // EventTest();
    windows_api_test();

    return 0;
}
